package no.rmz.chez.misc;

/**
 * An utility timer used to time how long various types of
 * activities takes.
 *
 */
public  final class Timer {

    /**
     *  The timestamp when the timer starts measuring time.
     */
    private  long startTime;


    /**
     * The timestamp when the timer ended measuring time.
     */
    private long endTime;

    /**
     * State variable: Has timing started?
     */
    private boolean isStarted = false;

    /**
     * State variable: Has timing ended?
     */
    private boolean isEnded   = false;

    /**
     * Start measuring time.
     *
     */
    public final void start() {
        if (isStarted) {
            throw new IllegalStateException("Illegal to start  a timer that is already started");
        }
        if (isEnded) {
            throw new IllegalStateException("Illegal to start a timer that has ended");
        }
        startTime =  System.currentTimeMillis();
        isStarted  = true;
    }


    /**
     * End measuring time.
     *
     */
    public synchronized  final void stop(){
        if (!isStarted) {
            throw new IllegalStateException("Illegal to stop  a timer that is not started");
        }
        if (isEnded) {
            throw new IllegalStateException("Illegal to stop a timer that has  already ended");
        }
        endTime = System.currentTimeMillis();
        isEnded = true;

    }

    /**
     * Get the duration either of the time so far, or if timing has stopped,
     * of the time to the end.
     * @return the duration since timing started.
     */
    public final long getDuration() {
        if (!isStarted) {
            throw new IllegalStateException("Illegal to measure duration of something that hasn�t started");
        }

        if (isEnded) {
            return endTime - startTime;
        } else {
            return System.currentTimeMillis() - startTime;
        }
    }

    /**
     * Describe the state of the timer as a string, mostly for
     * debugging purposes.
     */
    @Override
    public final String toString(){
        StringBuilder res = new StringBuilder();
        res.append("[Timer ");
        if (isStarted) {
            res.append("start = ").append(getStartTime()).append(", end = ").append(getEndTime()).append(", duration = ").append(getDuration());
            res.append(", isEnded =").append(isEnded);

        } else {
            res.append("Timer has not started");
        }
        res.append("]");
        return res.toString();

    }

    /**
     *  Returns the end-time of the timer, throws illegal
     *  state exception if attempted on non-ended timer.
     */
    public final long getEndTime() {
        if (!isEnded) {
            throw new IllegalStateException("Can�t get end-time of non-terminated timer");
        }
        return endTime;
    }

    /**
     * Is this timer ended?
     * @return ended?
     */
    public final boolean isEnded() {
        return isEnded;
    }

    /**
     * Is this timer started?
     * @return started?
     */
    public final boolean isStarted() {
        return isStarted;
    }

    /**
     * Return the time at which the timing started.
     * @return a time interval in milliseconds.
     */
    public final long getStartTime() {
        return startTime;
    }
}
